Instead of having a setter for the transform, have a GskTransformNode.
Most of the oprations that GTK does do not require a transform, so it
doesn't make sense to have it as a primary attribute.
Also, changing the transform requires updating the uniforms of the GL
renderer, so we're happy if we can avoid that.
gsk_render_node_unref
GskRenderNodeType
gsk_render_node_get_node_type
-gsk_render_node_set_transform
gsk_render_node_set_opacity
GskBlendMode
gsk_render_node_set_blend_mode
gsk_container_node_append_child
gsk_container_node_get_n_children
gsk_container_node_get_child
+gsk_transform_node_new
+gsk_transform_node_get_child
<SUBSECTION Standard>
GSK_IS_RENDER_NODE
GSK_RENDER_NODE
cairo_t *cr)
{
gboolean pop_group = FALSE;
- graphene_matrix_t mat;
- cairo_matrix_t ctm;
graphene_rect_t frame;
cairo_save (cr);
- gsk_render_node_get_transform (node, &mat);
- if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
- {
- GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
- ctm.xx, ctm.yx,
- ctm.xy, ctm.yy,
- ctm.x0, ctm.y0));
- cairo_transform (cr, &ctm);
- }
- else
- g_critical ("Invalid non-affine transformation for node %p", node);
-
gsk_render_node_get_bounds (node, &frame);
GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
frame.origin.x, frame.origin.y,
cairo_paint (cr);
}
break;
+
+ case GSK_TRANSFORM_NODE:
+ {
+ graphene_matrix_t mat;
+ cairo_matrix_t ctm;
+
+ gsk_transform_node_get_transform (node, &mat);
+ if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
+ {
+ GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
+ ctm.xx, ctm.yx,
+ ctm.xy, ctm.yy,
+ ctm.x0, ctm.y0));
+ cairo_transform (cr, &ctm);
+ }
+ else
+ g_critical ("Invalid non-affine transformation for node %p", node);
+
+ gsk_cairo_renderer_render_node (self, gsk_transform_node_get_child (node), cr);
+ }
+ break;
}
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
* @GSK_CONTAINER_NODE: A node containing a stack of children
* @GSK_CAIRO_NODE: A node drawing a #cairo_surface_t
* @GSK_TEXTURE_NODE: A node drawing a #GskTexture
+ * @GSK_TRANSFORM_NODE: A node that renders its child after applying a
+ * matrix transform
*
* The type of a node determines what the node is rendering.
*
GSK_NOT_A_RENDER_NODE = 0,
GSK_CONTAINER_NODE,
GSK_CAIRO_NODE,
- GSK_TEXTURE_NODE
+ GSK_TEXTURE_NODE,
+ GSK_TRANSFORM_NODE
} GskRenderNodeType;
/**
static void
gsk_gl_renderer_add_render_item (GskGLRenderer *self,
const graphene_matrix_t *projection,
- const graphene_matrix_t *parent_modelview,
+ const graphene_matrix_t *modelview,
GArray *render_items,
GskRenderNode *node,
RenderItem *parent)
{
graphene_rect_t viewport;
- graphene_matrix_t mv, transform;
graphene_rect_t bounds;
RenderItem item;
RenderItem *ritem = NULL;
item.max.z = 0.f;
/* The location of the item, in normalized world coordinates */
- gsk_render_node_get_transform (node, &transform);
- graphene_matrix_multiply (&transform, parent_modelview, &mv);
- graphene_matrix_multiply (&mv, &self->mvp, &item.mvp);
- item.z = project_item (projection, &mv);
+ graphene_matrix_multiply (modelview, &self->mvp, &item.mvp);
+ item.z = project_item (projection, modelview);
item.opacity = gsk_render_node_get_opacity (node);
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
{
GskRenderNode *child = gsk_container_node_get_child (node, i);
- gsk_gl_renderer_add_render_item (self, projection, &mv, render_items, child, ritem);
+ gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
}
}
return;
+ case GSK_TRANSFORM_NODE:
+ {
+ graphene_matrix_t transform, transformed_mv;
+
+ gsk_transform_node_get_transform (node, &transform);
+ graphene_matrix_multiply (&transform, modelview, &transformed_mv);
+ gsk_gl_renderer_add_render_item (self,
+ projection, &transformed_mv,
+ render_items,
+ gsk_transform_node_get_child (node),
+ ritem);
+ }
+ return;
+
case GSK_NOT_A_RENDER_NODE:
default:
return;
self->ref_count = 1;
- graphene_matrix_init_identity (&self->transform);
-
self->opacity = 1.0;
self->min_filter = GSK_SCALING_FILTER_NEAREST;
node->node_class->get_bounds (node, bounds);
}
-/**
- * gsk_render_node_set_transform:
- * @node: a #GskRenderNode
- * @transform: (nullable): a transformation matrix
- *
- * Sets the transformation matrix used when rendering the @node.
- *
- * Since: 3.90
- */
-void
-gsk_render_node_set_transform (GskRenderNode *node,
- const graphene_matrix_t *transform)
-{
- g_return_if_fail (GSK_IS_RENDER_NODE (node));
- g_return_if_fail (node->is_mutable);
-
- if (transform == NULL)
- graphene_matrix_init_identity (&node->transform);
- else
- graphene_matrix_init_from_matrix (&node->transform, transform);
-}
-
-/**
- * gsk_render_node_get_transform:
- * @node: a #GskRenderNode
- * @mv: (out caller-allocates): return location for the transform matrix
- *
- * Retrieves the transform matrix set using gsk_render_node_set_transform().
- *
- * Since: 3.90
- */
-void
-gsk_render_node_get_transform (GskRenderNode *node,
- graphene_matrix_t *mv)
-{
- g_return_if_fail (GSK_IS_RENDER_NODE (node));
- g_return_if_fail (mv != NULL);
-
- graphene_matrix_init_from_matrix (mv, &node->transform);
-}
-
/**
* gsk_render_node_set_opacity:
* @node: a #GskRenderNode
guint idx);
GDK_AVAILABLE_IN_3_90
-void gsk_render_node_set_transform (GskRenderNode *node,
+GskRenderNode * gsk_transform_node_new (GskRenderNode *child,
const graphene_matrix_t *transform);
+GDK_AVAILABLE_IN_3_90
+GskRenderNode * gsk_transform_node_get_child (GskRenderNode *node);
+
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_opacity (GskRenderNode *node,
double opacity);
return g_ptr_array_index (container->children, idx);
}
+/*** GSK_TRANSFORM_NODE ***/
+
+typedef struct _GskTransformNode GskTransformNode;
+
+struct _GskTransformNode
+{
+ GskRenderNode render_node;
+
+ GskRenderNode *child;
+ graphene_matrix_t transform;
+};
+
+static void
+gsk_transform_node_finalize (GskRenderNode *node)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+
+ gsk_render_node_unref (self->child);
+}
+
+static void
+gsk_transform_node_make_immutable (GskRenderNode *node)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+
+ gsk_render_node_make_immutable (self->child);
+}
+
+static void
+gsk_transform_node_get_bounds (GskRenderNode *node,
+ graphene_rect_t *bounds)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+ graphene_rect_t child_bounds;
+
+ gsk_render_node_get_bounds (self->child, &child_bounds);
+
+ graphene_matrix_transform_bounds (&self->transform,
+ &child_bounds,
+ bounds);
+}
+
+static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
+ GSK_TRANSFORM_NODE,
+ sizeof (GskTransformNode),
+ "GskTransformNode",
+ gsk_transform_node_finalize,
+ gsk_transform_node_make_immutable,
+ gsk_transform_node_get_bounds
+};
+
+/**
+ * gsk_transform_node_new:
+ * @child: The node to transform
+ * @transform: The transform to apply
+ *
+ * Creates a #GskRenderNode that will transform the given @child
+ * with the given @transform.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_transform_node_new (GskRenderNode *child,
+ const graphene_matrix_t *transform)
+{
+ GskTransformNode *self;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+ g_return_val_if_fail (transform != NULL, NULL);
+
+ self = (GskTransformNode *) gsk_render_node_new (&GSK_TRANSFORM_NODE_CLASS);
+
+ self->child = gsk_render_node_ref (child);
+ graphene_matrix_init_from_matrix (&self->transform, transform);
+
+ return &self->render_node;
+}
+
+/**
+ * gsk_transform_node_get_child:
+ * @node: a transform @GskRenderNode
+ *
+ * Gets the child node that is getting transformed by the given @node.
+ *
+ * Returns: (transfer none): The child that is getting transformed
+ **/
+GskRenderNode *
+gsk_transform_node_get_child (GskRenderNode *node)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE), NULL);
+
+ return self->child;
+}
+
+void
+gsk_transform_node_get_transform (GskRenderNode *node,
+ graphene_matrix_t *transform)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+
+ g_return_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE));
+
+ graphene_matrix_init_from_matrix (transform, &self->transform);
+}
+
GskScalingFilter min_filter;
GskScalingFilter mag_filter;
- /* Transformations applied to the node */
- graphene_matrix_t transform;
-
/* Bit fields; leave at the end */
gboolean is_mutable : 1;
};
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
-void gsk_render_node_get_transform (GskRenderNode *node,
- graphene_matrix_t *mv);
double gsk_render_node_get_opacity (GskRenderNode *node);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);
+void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform);
+
GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);
G_END_DECLS
self->render_passes = g_slist_prepend (self->render_passes, pass);
- gsk_vulkan_render_pass_add_node (pass, self, node);
+ gsk_vulkan_render_pass_add (pass, self, &self->mvp, node);
}
void
for (l = self->render_passes; l; l = l->next)
{
- gsk_vulkan_render_pass_draw (l->data, self, &self->mvp, self->pipeline, self->command_buffer);
+ gsk_vulkan_render_pass_draw (l->data, self, self->pipeline, self->command_buffer);
}
vkCmdEndRenderPass (self->command_buffer);
typedef enum {
GSK_VULKAN_OP_FALLBACK,
GSK_VULKAN_OP_SURFACE,
- GSK_VULKAN_OP_TEXTURE
+ GSK_VULKAN_OP_TEXTURE,
+ GSK_VULKAN_OP_BIND_MVP
} GskVulkanOpType;
struct _GskVulkanRenderOp
GskVulkanOpType type;
GskRenderNode *node; /* node that's the source of this op */
GskVulkanImage *source; /* source image to render */
+ graphene_matrix_t mvp; /* new mvp to set */
gsize vertex_offset; /* offset into vertex buffer */
gsize vertex_count; /* number of vertices */
gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
}
void
-gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskRenderNode *node)
+gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ const graphene_matrix_t *mvp,
+ GskRenderNode *node)
{
GskVulkanRenderOp op = {
.type = GSK_VULKAN_OP_FALLBACK,
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
{
- gsk_vulkan_render_pass_add_node (self, render, gsk_container_node_get_child (node, i));
+ gsk_vulkan_render_pass_add_node (self, render, mvp, gsk_container_node_get_child (node, i));
}
}
break;
+ case GSK_TRANSFORM_NODE:
+ {
+ graphene_matrix_t transform;
+
+ op.type = GSK_VULKAN_OP_BIND_MVP;
+ gsk_transform_node_get_transform (node, &transform);
+ graphene_matrix_multiply (&transform, mvp, &op.mvp);
+ g_array_append_val (self->render_ops, op);
+ gsk_vulkan_render_pass_add_node (self, render, &op.mvp, gsk_transform_node_get_child (node));
+ graphene_matrix_init_from_matrix (&op.mvp, mvp);
+ g_array_append_val (self->render_ops, op);
+ }
+ break;
+
}
return;
g_array_append_val (self->render_ops, op);
}
+void
+gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ const graphene_matrix_t *mvp,
+ GskRenderNode *node)
+{
+ GskVulkanRenderOp op = {
+ .type = GSK_VULKAN_OP_BIND_MVP,
+ .mvp = *mvp
+ };
+
+ g_array_append_val (self->render_ops, op);
+
+ gsk_vulkan_render_pass_add_node (self, render, mvp, node);
+}
+
static void
gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
GskVulkanRenderOp *op,
default:
g_assert_not_reached ();
+ case GSK_VULKAN_OP_BIND_MVP:
break;
}
}
default:
g_assert_not_reached ();
+ case GSK_VULKAN_OP_BIND_MVP:
+ op->vertex_offset = 0;
+ op->vertex_count = 0;
break;
}
default:
g_assert_not_reached ();
+ case GSK_VULKAN_OP_BIND_MVP:
break;
}
}
void
gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
GskVulkanRender *render,
- const graphene_matrix_t *parent_mvp,
GskVulkanPipeline *pipeline,
VkCommandBuffer command_buffer)
{
GskVulkanRenderOp *op;
- graphene_matrix_t transform, mvp;
float float_matrix[16];
guint i;
{
op = &g_array_index (self->render_ops, GskVulkanRenderOp, i);
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->descriptor_set_index)
- },
- 0,
- NULL);
-
- gsk_render_node_get_transform (op->node, &transform);
- graphene_matrix_multiply (&transform, parent_mvp, &mvp);
- graphene_matrix_to_float (&mvp, float_matrix);
-
- vkCmdPushConstants (command_buffer,
- gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
- VK_SHADER_STAGE_VERTEX_BIT,
- 0,
- sizeof (float_matrix),
- &float_matrix);
-
- vkCmdDraw (command_buffer,
- op->vertex_count, 1,
- op->vertex_offset, 0);
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_SURFACE:
+ case GSK_VULKAN_OP_TEXTURE:
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ vkCmdDraw (command_buffer,
+ op->vertex_count, 1,
+ op->vertex_offset, 0);
+ break;
+
+ case GSK_VULKAN_OP_BIND_MVP:
+ graphene_matrix_to_float (&op->mvp, float_matrix);
+ vkCmdPushConstants (command_buffer,
+ gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0,
+ sizeof (float_matrix),
+ &float_matrix);
+
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
}
}
GskVulkanRenderPass * gsk_vulkan_render_pass_new (GdkVulkanContext *context);
void gsk_vulkan_render_pass_free (GskVulkanRenderPass *self);
-void gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
+void gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
GskVulkanRender *render,
+ const graphene_matrix_t*mvp,
GskRenderNode *node);
void gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
GskVulkanRender *render);
void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
GskVulkanRender *render,
- const graphene_matrix_t*root_mvp,
GskVulkanPipeline *pipeline,
VkCommandBuffer command_buffer);
GtkCssImageBuiltinType builtin_type)
{
const GtkCssValue *shadows, *transform;
- graphene_matrix_t transform_matrix, m1, m2, m3, saved_matrix;
- GtkCssImage *image;
static gboolean shadow_warning;
+ graphene_matrix_t transform_matrix;
+ GtkCssImage *image;
g_return_if_fail (GTK_IS_CSS_STYLE (style));
g_return_if_fail (snapshot != NULL);
if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
return;
- graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot));
-
- /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
- graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0));
- graphene_matrix_multiply (&transform_matrix, &m1, &m3);
- graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
- graphene_matrix_multiply (&m2, &m3, &m1);
- gtk_snapshot_transform (snapshot, &m1);
-
if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
{
g_warning ("Painting shadows not implemented for textures yet.");
shadow_warning = TRUE;
}
- gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
- gtk_snapshot_set_transform (snapshot, &saved_matrix);
+ if (graphene_matrix_is_identity (&transform_matrix))
+ {
+ gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
+ }
+ else
+ {
+ graphene_matrix_t m1, m2, m3;
+ GskRenderNode *transform_node, *container_node;
+ double offset_x, offset_y;
+
+ gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+ /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
+ graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + height / 2.0, 0));
+ graphene_matrix_multiply (&transform_matrix, &m1, &m3);
+ graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
+ graphene_matrix_multiply (&m2, &m3, &m1);
+
+ container_node = gsk_container_node_new ();
+ gsk_render_node_set_name (container_node, "CSS Icon Transform Container");
+ transform_node = gsk_transform_node_new (container_node, &m1);
+ gsk_render_node_set_name (transform_node, "CSS Icon Transform");
+ gtk_snapshot_append_node (snapshot, transform_node);
+
+ gtk_snapshot_push_node (snapshot, container_node);
+ gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
+ gtk_snapshot_pop (snapshot);
+ }
}
static gboolean
double texture_scale)
{
const GtkCssValue *shadows, *transform;
- graphene_matrix_t transform_matrix, translate, matrix, saved_matrix;
+ graphene_matrix_t transform_matrix;
graphene_rect_t bounds;
- GskRenderNode *node;
+ GskRenderNode *icon_node, *transform_node;
double width, height;
static gboolean shadow_warning;
if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
return;
- graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot));
-
- /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
- graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0));
- graphene_matrix_multiply (&transform_matrix, &translate, &matrix);
- graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
- graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1);
- gtk_snapshot_transform (snapshot, &matrix);
-
- graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
-
- node = gsk_texture_node_new (texture, &bounds);
- gsk_render_node_set_name (node, "Icon");
- gtk_snapshot_append_node (snapshot, node);
if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
{
g_warning ("Painting shadows not implemented for textures yet.");
shadow_warning = TRUE;
}
- gsk_render_node_unref (node);
- gtk_snapshot_set_transform (snapshot, &saved_matrix);
+ if (graphene_matrix_is_identity (&transform_matrix))
+ {
+ double offset_x, offset_y;
+
+ gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+ graphene_rect_init (&bounds,
+ offset_x, offset_y,
+ gsk_texture_get_width (texture) / texture_scale,
+ gsk_texture_get_height (texture) / texture_scale);
+ icon_node = gsk_texture_node_new (texture, &bounds);
+ gsk_render_node_set_name (icon_node, "Icon");
+
+ gtk_snapshot_append_node (snapshot, icon_node);
+ }
+ else
+ {
+ graphene_matrix_t translate, matrix;
+ double offset_x, offset_y;
+
+ gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+ /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
+ graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + height / 2.0, 0));
+ graphene_matrix_multiply (&transform_matrix, &translate, &matrix);
+ graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
+ graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1);
+
+ graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
+ icon_node = gsk_texture_node_new (texture, &bounds);
+ gsk_render_node_set_name (icon_node, "Icon");
+
+ transform_node = gsk_transform_node_new (icon_node, &matrix);
+ gsk_render_node_set_name (transform_node, "Icon Transform");
+ gtk_snapshot_append_node (snapshot, transform_node);
+
+ gsk_render_node_unref (icon_node);
+ gsk_render_node_unref (transform_node);
+ }
}
* transformations.
*
* The node at the top of the stack is the the one that gtk_snapshot_append_node()
- * operates on. Use the gtk_snapshot_push_() and gtk_snapshot_pop() functions to
+ * operates on. Use the gtk_snapshot_push() and gtk_snapshot_pop() functions to
* change the current node.
*
* The only way to obtain a #GtkSnapshot object is as an argument to
state->node = node;
state->parent = parent;
- graphene_matrix_init_identity (&state->transform);
return state;
}
g_slice_free (GtkSnapshotState, state);
}
-static void
-gtk_snapshot_state_set_transform (GtkSnapshotState *state,
- const graphene_matrix_t *transform)
-{
- graphene_matrix_init_from_matrix (&state->transform, transform);
-
- state->world_is_valid = FALSE;
-}
-
-static const graphene_matrix_t *
-gtk_snapshot_state_get_world_transform (GtkSnapshotState *state)
-{
- if (!state->world_is_valid)
- {
- if (state->parent)
- graphene_matrix_multiply (gtk_snapshot_state_get_world_transform (state->parent),
- &state->transform,
- &state->world_transform);
- else
- graphene_matrix_init_from_matrix (&state->world_transform, &state->transform);
-
- state->world_is_valid = TRUE;
- }
-
- return &state->world_transform;
-}
-
void
gtk_snapshot_init (GtkSnapshot *snapshot,
GskRenderer *renderer,
* @snapshot: a #GtkSnapshot
* @node: the render node to push
*
- * Appends @node to the current render node of @snapshot,
- * and makes @node the new current render node.
+ * Makes @node the new current render node. You are responsible for adding
+ * @node to the snapshot.
*
* Since: 3.90
*/
{
g_return_if_fail (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE);
- gtk_snapshot_append_node (snapshot, node);
-
snapshot->state = gtk_snapshot_state_new (snapshot->state, node);
}
g_free (str);
}
+ gtk_snapshot_append_node (snapshot, node);
gtk_snapshot_push_node (snapshot, node);
gsk_render_node_unref (node);
}
}
/**
- * gtk_snapshot_set_transform:
- * @snapshot: a #GtkSnapshot
- * @transform: a transformation matrix
+ * gtk_snapshot_translate_2d:
+ * @snapshot: a $GtkSnapshot
+ * @x: horizontal translation
+ * @y: vertical translation
*
- * Replaces the current transformation with the given @transform.
+ * Appends a translation by (@x, @y) to the current transformation.
*
* Since: 3.90
*/
void
-gtk_snapshot_set_transform (GtkSnapshot *snapshot,
- const graphene_matrix_t *transform)
+gtk_snapshot_translate_2d (GtkSnapshot *snapshot,
+ int x,
+ int y)
{
- g_return_if_fail (snapshot->state != NULL);
-
- gtk_snapshot_state_set_transform (snapshot->state, transform);
+ snapshot->state->translate_x += x;
+ snapshot->state->translate_y += y;
}
/**
- * gtk_snapshot_transform:
+ * gtk_snapshot_get_offset:
* @snapshot: a #GtkSnapshot
- * @transform: a transformation matrix
+ * @x: (out allow-none): return location for x offset
+ * @y: (out allow-none): return location for y offset
*
- * Appends @transform to the current transformation.
- *
- * Since: 3.90
- */
-void
-gtk_snapshot_transform (GtkSnapshot *snapshot,
- const graphene_matrix_t *transform)
-{
- graphene_matrix_t result;
-
- g_return_if_fail (snapshot->state != NULL);
-
- graphene_matrix_multiply (transform, &snapshot->state->transform, &result);
- gtk_snapshot_state_set_transform (snapshot->state, &result);
-}
-
-/**
- * gtk_snapshot_translate_2d:
- * @snapshot: a $GtkSnapshot
- * @x: horizontal translation
- * @y: vertical translation
+ * Queries the offset managed by @snapshot. This offset is the
+ * accumulated sum of calls to gtk_snapshot_translate_2d().
*
- * Appends a translation by (@x, @y) to the current transformation.
+ * Use this offset to determine how to offset nodes that you
+ * manually add to the snapshot using
+ * gtk_snapshot_append_node().
*
- * Since: 3.90
- */
+ * Note that other functions that add nodes for you, such as
+ * gtk_snapshot_append_cairo_node() will add this offset for
+ * you.
+ **/
void
-gtk_snapshot_translate_2d (GtkSnapshot *snapshot,
- int x,
- int y)
+gtk_snapshot_get_offset (GtkSnapshot *snapshot,
+ double *x,
+ double *y)
{
- graphene_matrix_t transform;
- graphene_point3d_t point;
+ if (x)
+ *x = snapshot->state->translate_x;
- graphene_point3d_init (&point, x, y, 0);
- graphene_matrix_init_translate (&transform, &point);
- gtk_snapshot_transform (snapshot, &transform);
+ if (y)
+ *y = snapshot->state->translate_y;
}
/**
if (snapshot->state)
{
gsk_container_node_append_child (snapshot->state->node, node);
- gsk_render_node_set_transform (node, &snapshot->state->transform);
}
else
{
...)
{
GskRenderNode *node;
+ graphene_rect_t real_bounds;
+ cairo_t *cr;
g_return_val_if_fail (snapshot != NULL, NULL);
g_return_val_if_fail (bounds != NULL, NULL);
- node = gsk_cairo_node_new (bounds);
+ graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds);
+ node = gsk_cairo_node_new (&real_bounds);
if (name)
{
gtk_snapshot_append_node (snapshot, node);
gsk_render_node_unref (node);
- return gsk_cairo_node_get_draw_context (node, snapshot->renderer);
+ cr = gsk_cairo_node_get_draw_context (node, snapshot->renderer);
+
+ cairo_translate (cr, snapshot->state->translate_x, snapshot->state->translate_y);
+
+ return cr;
}
static void
gtk_snapshot_clips_rect (GtkSnapshot *snapshot,
const graphene_rect_t *bounds)
{
+ graphene_rect_t offset_bounds;
cairo_rectangle_int_t rect;
- if (snapshot->state)
- {
- const graphene_matrix_t *world;
- graphene_rect_t transformed;
-
- world = gtk_snapshot_state_get_world_transform (snapshot->state);
-
- graphene_matrix_transform_bounds (world, bounds, &transformed);
- rectangle_init_from_graphene (&rect, &transformed);
- }
- else
- {
- rectangle_init_from_graphene (&rect, bounds);
- }
+ graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &offset_bounds);
+ rectangle_init_from_graphene (&rect, &offset_bounds);
return cairo_region_contains_rectangle (snapshot->clip_region, &rect) == CAIRO_REGION_OVERLAP_OUT;
}
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_pop (GtkSnapshot *snapshot);
-GDK_AVAILABLE_IN_3_90
-void gtk_snapshot_set_transform (GtkSnapshot *snapshot,
- const graphene_matrix_t *transform);
-GDK_AVAILABLE_IN_3_90
-void gtk_snapshot_transform (GtkSnapshot *snapshot,
- const graphene_matrix_t *transform);
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_translate_2d (GtkSnapshot *snapshot,
int x,
int y);
+GDK_AVAILABLE_IN_3_90
+void gtk_snapshot_get_offset (GtkSnapshot *snapshot,
+ double *x,
+ double *y);
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_append_node (GtkSnapshot *snapshot,
GskRenderNode *node;
- graphene_matrix_t transform;
- graphene_matrix_t world_transform;
- guint world_is_valid : 1;
+ double translate_x;
+ double translate_y;
};
struct _GtkSnapshot {
...) G_GNUC_PRINTF (4, 5);
GskRenderNode * gtk_snapshot_finish (GtkSnapshot *state);
-static inline const graphene_matrix_t *
-gtk_snapshot_get_transform (const GtkSnapshot *snapshot)
-{
- return &snapshot->state->transform;
-}
-
G_END_DECLS
#endif /* __GTK_SNAPSHOT_PRIVATE_H__ */
/* no children */
break;
+ case GSK_TRANSFORM_NODE:
+ append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1);
+ break;
+
case GSK_CONTAINER_NODE:
{
gint elt_index;
populate_render_node_properties (GtkListStore *store,
GskRenderNode *node)
{
- graphene_matrix_t m;
graphene_rect_t bounds;
- GString *s;
int i;
char *tmp;
GEnumClass *class;
gtk_list_store_clear (store);
- gsk_render_node_get_transform (node, &m);
-
- s = g_string_new ("");
- for (i = 0; i < 4; i++)
- {
- if (i > 0)
- g_string_append (s, "\n");
- g_string_append_printf (s, "| %+.6f %+.6f %+.6f %+.6f |",
- graphene_matrix_get_value (&m, i, 0),
- graphene_matrix_get_value (&m, i, 1),
- graphene_matrix_get_value (&m, i, 2),
- graphene_matrix_get_value (&m, i, 3));
- }
-
- gtk_list_store_insert_with_values (store, NULL, -1,
- 0, "Transform",
- 1, s->str,
- -1);
-
- g_string_free (s, TRUE);
-
gsk_render_node_get_bounds (node, &bounds);
tmp = g_strdup_printf ("%.6f x %.6f + %.6f + %.6f",